#define D_SCL_SECURE_NO_WARNINGS
#define _USE_MATH_DEFINES
#include <math.h>
#include <vector>
using namespace std;

#include <QtGui>
#include "Data.h"
#include "Gfx.h"
#include <gl\GLU.h>
//#include "bmp.h"
#include "Helper.h"

CGfx::CGfx(CData* pData_/*=NULL*/)
:_pData(pData_),_eCurrExptState(BeforeRun)
{
}

CGfx::~CGfx()
{
}

void CGfx::initGL()
{
    // from InitGfx
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_POINT_SMOOTH);
    glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
    glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
    glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
    //glHint(GL_GENERATE_MIPMAP_HINT, GL_NICEST);

    glEnable(GL_BLEND);
    glDepthFunc( GL_LESS );

    //loadTextures();

    // following come from InitAll
    glPolygonMode(GL_BACK,GL_LINE);
    glCullFace(GL_FRONT);
    glFrontFace(GL_CCW);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    //float fWidth = _pData->screenWidth();
    //float fHeight = _pData->screenHeight();

    //gluPerspective( _pData->gfxFOVy(), fWidth/fHeight, _pData->gfxNear(), _pData->gfxFar() );
    // following come from InitUpdateDuringRun
    glClearColor(_pData->GetBackColor()[0],_pData->GetBackColor()[1],_pData->GetBackColor()[2],0.f);

    _pData->precompute();

    return;
}

void CGfx::updateStatus()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    switch (_eCurrExptState)
    {
    case BeforeRun:
        {
            if (_pData->allTrialsFinished())
            {
                // end of last trial, quit program
                _eCurrExptState = ExpEnd;
                break;
            } 
            LoadParametersFromScript();
            // precompute before all trials
            _pData->precomputeEachTrial();
            initDisplayList();
            _eCurrExptState = OnBreak;
        }
        break;
    case OnBreak:
        {
            //renderBreak();
            while(!_pData->preRunFinished())
            {
                _pData->updateOutput(1);
                offlineRender();
                _pData->setTimeIdx()++;
            }
            
            _pData->updateOutput(1);
            renderNormalView();

            //because disturbances were updated for every trial
            if(_pData->CheckForTriggerHelper())
            {
                _eCurrExptState = NormalView;
            }
        }
        break;
    case NormalView:
        {
            if (_pData->allTrialsFinished()||_pData->trialFinished())
            {
                _eCurrExptState = AfterRun;
            }
            else
            {    
                _pData->updateOutput();
                renderNormalView();
                _pData->setTimeIdx()++;
            }
        }
        break;
    case BirdView:
        {
            if (_pData->allTrialsFinished()||_pData->trialFinished())
            {
                _eCurrExptState = AfterRun;
            }
            else
            {    
                _pData->updateOutput();
                renderBirdView();
                _pData->setTimeIdx()++;
            }
            break;
        }
    case AfterRun:
        {
            _pData->saveToFile();
            _pData->afterCompute();
            if (_pData->allTrialsFinished())
            {
                // end of last trial, quit program
                _eCurrExptState = ExpEnd;
            } 
            else
            {
                _pData->setTrialIdx()++;
                _eCurrExptState = BeforeRun;
            }
        }
        break;
    case ExpEnd:
        //throw exception("End of the experiment.");
        //QMessageBox::warning(this,QString("Experiment ends"),QString("All trials finished."),QMessageBox::Yes); 
        //_cTimer->stop();   
        //setDatatLoaded()=false;
        //_pData->SaveToFile();
        break;
    }
}

void CGfx::renderBreak()
{
    //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    //UpdateObserverCenterPos();
    //renderRest();

    //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();									// Reset The Current Modelview Matrix
    glOrtho(0,1.0,0.0,1.0,-1.0,1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    //glTranslatef(0.0f,0.0f,-6.0f);						// Move One Unit Into The Screen
    //// Pulsing Colors Based On Text Position
    glColor3f(1.0f,1.0f,1.0f);

    return;
}

void CGfx::renderNormalView()
{
    updateObserver(_pData->timeIdx());
    renderObj();
}

void CGfx::offlineRender()
{
    updateObserver(_pData->timeIdx());
}

void CGfx::resizeGL(int nWidth_, int nHeight_)
{
    if (nHeight_==0)                                        // Prevent A Divide By Zero By
    {
        nHeight_=1;                                        // Making Height Equal One
    }


    glMatrixMode(GL_PROJECTION);                        // Select The Projection Matrix
    glLoadIdentity();                                    // Reset The Projection Matrix

    // Calculate The Aspect Ratio Of The Window
    gluPerspective(_pData->gfxFOVy(),_pData->gfxAspectRatio(), _pData->gfxNear(), _pData->gfxFar());
    glViewport(0,0,nWidth_,nHeight_);                        // Reset The Current Viewport
    //_pData->setGfxFOVx() = atan(nWidth_*tan(_pData->gfxFOVy()/2*DEG2RAD)/nHeight_)*2*RAD2DEG;

    glMatrixMode(GL_MODELVIEW);                            // Select The Modelview Matrix
    glLoadIdentity();                                    // Reset Thqe Modelview Matrix

    //int side = qMin(width, height);
    //glViewport((width - side) / 2, (height - side) / 2, side, side);

    //glMatrixMode(GL_PROJECTION);
    //glLoadIdentity();
    //glFrustum(-1.0, +1.0, -1.0, 1.0, 5.0, 60.0);
    //glMatrixMode(GL_MODELVIEW);
    //glLoadIdentity();
    //glTranslated(0.0, 0.0, -40.0);
}


void CGfx::catchTriggerRiseEdge()
{
    if(_pData->flyBox())
    {
        bool bTrigger = _pData->CheckForTriggerHelper();

        if(_bTriggerLastFrame != bTrigger && _bTriggerLastFrame == false) //catch the up the rising edge
            //change                         last frame must be false or 0
        {
            setShowScene() = !showScene(); // show the tunnel
        }
        _bTriggerLastFrame = bTrigger;
    }
}

void CGfx::renderBirdView()
{
    updateBirdObserver(_pData->timeIdx());
    renderObj();
}